/*
 * Window.java
 *
 * Created on August 12, 2007, 8:05 PM
 */
package com.afaker.rss.gui;

import com.afaker.rss.html.CascadeStyleSheet;
import com.afaker.rss.feed.biz.FeedUpdatedListener;
import com.afaker.rss.feed.EntrySet;
import com.afaker.rss.feed.ChannelList;
import com.afaker.rss.gui.tree.RSSTreeHelper;
import com.afaker.rss.gui.tree.RSSTreeCellRenderer;
import com.afaker.rss.gui.tree.RSSTreeNode;
import com.afaker.rss.search.Searcher;
import com.afaker.rss.gui.table.listener.TableDataListener;
import com.afaker.rss.gui.table.XMLTableModel;
import com.afaker.rss.gui.table.SortableTableModel;
import com.afaker.rss.gui.table.FilterableTableModel;
import com.afaker.rss.gui.dnd.DropHandler;
import com.afaker.rss.gui.dnd.DragHandler;
import com.afaker.rss.gui.action.MenuAction;
import com.afaker.rss.*;
import com.afaker.rss.common.ClientUpdater;
import com.afaker.rss.common.GeneralUtils;
import com.afaker.rss.context.ApplicationContext;
import com.afaker.rss.context.Context;
import com.afaker.rss.context.ResourceContext;
import com.afaker.rss.search.Indexer;
import com.sun.syndication.io.FeedException;
import com.afaker.rss.xml.XMLDocumentFactory;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.table.JTableHeader;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.StyleSheet;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.search.Hits;

/**
 *
 * @author  bruce
 */
public class Window extends javax.swing.JFrame implements TreeSelectionListener, TableDataListener, ListSelectionListener, HyperlinkListener,
        FeedUpdatedListener {

    /** Creates new form Window */
    public Window() {
        channelList = new ChannelList(Context.CURRENT_DIR + resourceContext.getProperty("channel.file"));
        treeModel = new DefaultTreeModel(root);
        initComponents();
        this.setTitle(applicationContext.getProperty("app.name"));
        fileMenu.setText(applicationContext.getProperty("file.menu"));
        helpMenu.setText(applicationContext.getProperty("help.menu"));
        helpContentMenuItem.setText(applicationContext.getProperty("help.help.menu"));
        homePageMenuItem.setText(applicationContext.getProperty("help.homepage.menu"));
        checkUpdateMenuItem.setText(applicationContext.getProperty("help.update.menu"));

        xml.build(resourceContext.getProperty("favorite.file"));
        JButton a = toolBar.add(newCh);
        a.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
        a.setFocusPainted(false);
        a.setOpaque(false);
        a = toolBar.add(newDir);
        a.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
        a.setFocusPainted(false);
        a.setOpaque(false);
        a = toolBar.add(delete);
        a.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
        a.setFocusPainted(false);
        a.setOpaque(false);

        a = toolBar.add(update);
        a.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
        a.setFocusPainted(false);
        a.setOpaque(false);
        /*a = toolBar.add(updateAll);
        a.setBorder(BorderFactory.createEmptyBorder(0,3,0,3));
        a.setFocusPainted(false);
        a.setOpaque(false);*/

        treeHelper = new RSSTreeHelper(tree);
        treeHelper.setTreeWithXML(xml);
        treeHelper.expandAll(true);
        //ArrayList<RSSTreeNode> feedNodes = treeHelper.getFeedTreeNode();

        MenuAction.setNecessaryInformation(tree, toolBar, this, channelList, tableModel, xml);

        tree.addTreeSelectionListener(this);

        tableModel.addTableDataListener(this);
        listModel = table.getSelectionModel();
        listModel.addListSelectionListener(this);
        JTableHeader header = table.getTableHeader();

        header.addMouseListener(sortModel.new ColumnListener(table));

        //Startup the updater
        Thread temp = new Thread(new Runnable() {

            public void run() {
                updater = new Updater(channelList);
                updater.addFeedUpdatedListener(Window.this);
                Thread thread = new Thread(updater);
                thread.start();
            }
        });
        temp.start();

        //Unenable the updateAll Menu
        updateAllMenu.setVisible(false);

        css = new CascadeStyleSheet(resourceContext.getProperty("css.dir") +
                resourceContext.getProperty("current.css"));
        HTMLDocument doc = (HTMLDocument) textArea.getDocument();
        try {
            File file = new File(".");
            doc.setBase(new URL("file", "localhost", file.getAbsolutePath()));
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
        StyleSheet style;
        style = doc.getStyleSheet();
        style.addRule(css.getStyle());
        textArea.addHyperlinkListener(this);
        tree.getTransferHandler();

        DropHandler drop = new DropHandler(tree);
        DragHandler drag = new DragHandler(tree);
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(new InnerWindowAdapter());
    }

    class InnerWindowAdapter extends WindowAdapter {

        @Override
        public void windowClosing(WindowEvent e) {
            int response = -1;
            if (clientUpdater != null) {
                if (!clientUpdater.isDone()) {
                    response = JOptionPane.showInternalConfirmDialog(Window.this.getContentPane(),
                            applicationContext.getProperty("downlaod.cancel.tip"),
                            applicationContext.getProperty("app.name"),
                            JOptionPane.OK_CANCEL_OPTION,
                            JOptionPane.QUESTION_MESSAGE);
                } else {
                    GeneralUtils.copyFile(ClientUpdater.DOWNLOAD_DIR + ClientUpdater.FILE_NAME, "./RSS_Client.jar");
                    response = JOptionPane.OK_OPTION;
                }
            }
            if (response == JOptionPane.OK_OPTION || clientUpdater == null) {
                System.exit(0);
            }
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        popMenu = new javax.swing.JPopupMenu();
        add = new javax.swing.JMenu();
        addChannel = new javax.swing.JMenuItem();
        addCategory = new javax.swing.JMenuItem();
        deleteMenu = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JSeparator();
        updateMenu = new javax.swing.JMenuItem();
        updateAllMenu = new javax.swing.JMenuItem();
        toolBar2 = new javax.swing.JToolBar();
        tabHeader = new javax.swing.JPanel();
        jLabel3 = new javax.swing.JLabel();
        jButton1 = new javax.swing.JButton();
        tablePopMenu = new javax.swing.JPopupMenu();
        deleteEntryMenu = new javax.swing.JMenuItem();
        starMenu = new javax.swing.JMenuItem();
        jPanel2 = new javax.swing.JPanel();
        searchPopMenu = new javax.swing.JPopupMenu();
        summarySearch = new javax.swing.JMenuItem();
        titleSearch = new javax.swing.JMenuItem();
        jSeparator2 = new javax.swing.JSeparator();
        googleSearch = new javax.swing.JMenuItem();
        technoratiSearch = new javax.swing.JMenuItem();
        jLabel1 = new javax.swing.JLabel();
        searchField = new javax.swing.JTextField();
        urlField = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        toolBarPanel = new javax.swing.JPanel();
        toolBar = new javax.swing.JToolBar();
        jButton2 = new javax.swing.JButton();
        jPanel3 = new javax.swing.JPanel();
        jSplitPane1 = new javax.swing.JSplitPane();
        jScrollPane1 = new javax.swing.JScrollPane();
        tree = new javax.swing.JTree();
        tabbedPane = new javax.swing.JTabbedPane();
        jSplitPane2 = new javax.swing.JSplitPane();
        jPanel1 = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        table = new javax.swing.JTable();
        titleLabel = new javax.swing.JLabel();
        filter = new javax.swing.JComboBox();
        jScrollPane3 = new javax.swing.JScrollPane();
        textArea = new javax.swing.JEditorPane();
        bottomPanel = new javax.swing.JPanel();
        progressBar = new javax.swing.JProgressBar();
        menuBar = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        helpMenu = new javax.swing.JMenu();
        helpContentMenuItem = new javax.swing.JMenuItem();
        jSeparator7 = new javax.swing.JSeparator();
        homePageMenuItem = new javax.swing.JMenuItem();
        checkUpdateMenuItem = new javax.swing.JMenuItem();

        add.setText("Add"); // NOI18N

        addChannel.setText("Add Channel"); // NOI18N
        addChannel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addChannelActionPerformed(evt);
            }
        });
        add.add(addChannel);

        addCategory.setText("Add Category"); // NOI18N
        addCategory.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addCategoryActionPerformed(evt);
            }
        });
        add.add(addCategory);

        popMenu.add(add);

        deleteMenu.setText("Delete"); // NOI18N
        deleteMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                deleteMenuActionPerformed(evt);
            }
        });
        popMenu.add(deleteMenu);
        popMenu.add(jSeparator1);

        updateMenu.setText("Update"); // NOI18N
        updateMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateMenuActionPerformed(evt);
            }
        });
        popMenu.add(updateMenu);

        updateAllMenu.setText("Update All"); // NOI18N
        updateAllMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAllMenuActionPerformed(evt);
            }
        });
        popMenu.add(updateAllMenu);

        jLabel3.setText("jLabel3"); // NOI18N

        jButton1.setMargin(new java.awt.Insets(2, 2, 2, 2));

        javax.swing.GroupLayout tabHeaderLayout = new javax.swing.GroupLayout(tabHeader);
        tabHeader.setLayout(tabHeaderLayout);
        tabHeaderLayout.setHorizontalGroup(
            tabHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(tabHeaderLayout.createSequentialGroup()
                .addComponent(jLabel3)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
        tabHeaderLayout.setVerticalGroup(
            tabHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(tabHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(jLabel3, javax.swing.GroupLayout.Alignment.TRAILING)
                .addComponent(jButton1, javax.swing.GroupLayout.Alignment.TRAILING))
        );

        deleteEntryMenu.setText("Delete the news"); // NOI18N
        deleteEntryMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                deleteEntryMenuActionPerformed(evt);
            }
        });
        tablePopMenu.add(deleteEntryMenu);

        starMenu.setText("Starred"); // NOI18N
        tablePopMenu.add(starMenu);

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 100, Short.MAX_VALUE)
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 100, Short.MAX_VALUE)
        );

        summarySearch.setText("Search By News Summary"); // NOI18N
        searchPopMenu.add(summarySearch);

        titleSearch.setText("Search By News Title"); // NOI18N
        searchPopMenu.add(titleSearch);
        searchPopMenu.add(jSeparator2);

        googleSearch.setText("Search By Google"); // NOI18N
        searchPopMenu.add(googleSearch);

        technoratiSearch.setText("Search By Technorati"); // NOI18N
        searchPopMenu.add(technoratiSearch);

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("RSS - Rolling Stone Soul");

        jLabel1.setText("FeedURL:"); // NOI18N

        searchField.setPreferredSize(new java.awt.Dimension(4, 20));
        searchField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                searchFieldActionPerformed(evt);
            }
        });

        urlField.setText("http://"); // NOI18N
        urlField.setPreferredSize(new java.awt.Dimension(43, 20));
        urlField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                urlFieldActionPerformed(evt);
            }
        });

        jLabel2.setText("Search News"); // NOI18N

        javax.swing.GroupLayout toolBarPanelLayout = new javax.swing.GroupLayout(toolBarPanel);
        toolBarPanel.setLayout(toolBarPanelLayout);
        toolBarPanelLayout.setHorizontalGroup(
            toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(toolBar, javax.swing.GroupLayout.DEFAULT_SIZE, 606, Short.MAX_VALUE)
        );
        toolBarPanelLayout.setVerticalGroup(
            toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(toolBar, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
        );

        jButton2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/image/down.gif"))); // NOI18N
        jButton2.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        jButton2.setFocusPainted(false);
        jButton2.setIconTextGap(0);
        jButton2.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jButton2MouseClicked(evt);
            }
        });

        jSplitPane1.setDividerLocation(150);
        jSplitPane1.setOneTouchExpandable(true);
        jSplitPane1.setPreferredSize(new java.awt.Dimension(210, 365));

        tree.setModel(treeModel);
        tree.setToolTipText(""); // NOI18N
        tree.setCellRenderer(renderer);
        tree.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                treeMousePressed(evt);
            }
        });
        jScrollPane1.setViewportView(tree);

        jSplitPane1.setLeftComponent(jScrollPane1);

        tabbedPane.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                tabbedPaneMouseClicked(evt);
            }
        });

        jSplitPane2.setDividerLocation(170);
        jSplitPane2.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        jSplitPane2.setOneTouchExpandable(true);

        tableModel = new XMLTableModel();
        filterModel = new FilterableTableModel(tableModel);
        sortModel = new SortableTableModel(filterModel);
        table.setModel(sortModel);
        table.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                tableMousePressed(evt);
            }
        });
        jScrollPane2.setViewportView(table);

        titleLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);

        filter.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "All News", "Unread", "Starred" }));
        filter.setPreferredSize(new java.awt.Dimension(68, 20));
        filter.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                filterActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 442, Short.MAX_VALUE)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                .addComponent(titleLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 316, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(filter, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(filter, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(titleLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 144, Short.MAX_VALUE))
        );

        jSplitPane2.setLeftComponent(jPanel1);

        textArea.setContentType("text/html"); // NOI18N
        textArea.setEditable(false);
        jScrollPane3.setViewportView(textArea);

        jSplitPane2.setRightComponent(jScrollPane3);

        tabbedPane.addTab("RSS - Rolling Stone Soul", jSplitPane2);

        jSplitPane1.setRightComponent(tabbedPane);
        tabbedPane.getAccessibleContext().setAccessibleName("RSS - Rolling Stone Soul"); // NOI18N

        javax.swing.GroupLayout bottomPanelLayout = new javax.swing.GroupLayout(bottomPanel);
        bottomPanel.setLayout(bottomPanelLayout);
        bottomPanelLayout.setHorizontalGroup(
            bottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, bottomPanelLayout.createSequentialGroup()
                .addContainerGap(456, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
        bottomPanelLayout.setVerticalGroup(
            bottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        );

        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(bottomPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 606, Short.MAX_VALUE)
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
                .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 340, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(bottomPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );

        fileMenu.setText("File"); // NOI18N
        menuBar.add(fileMenu);

        helpMenu.setText("Help");

        helpContentMenuItem.setText("Help Content");
        helpContentMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                helpContentMenuItemActionPerformed(evt);
            }
        });
        helpMenu.add(helpContentMenuItem);
        helpMenu.add(jSeparator7);

        homePageMenuItem.setText("Home Page");
        helpMenu.add(homePageMenuItem);

        checkUpdateMenuItem.setText("Check for Update");
        checkUpdateMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                checkUpdateMenuItemActionPerformed(evt);
            }
        });
        helpMenu.add(checkUpdateMenuItem);

        menuBar.add(helpMenu);

        setJMenuBar(menuBar);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(toolBarPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(urlField, javax.swing.GroupLayout.DEFAULT_SIZE, 215, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(searchField, javax.swing.GroupLayout.PREFERRED_SIZE, 188, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE))
            .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(toolBarPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(32, 32, 32)
                        .addComponent(searchField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(32, 32, 32)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(urlField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jLabel2)))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(34, 34, 34)
                        .addComponent(jLabel1)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents
    private void jButton2MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jButton2MouseClicked
// TODO add your handling code here:
        Point p = searchField.getLocationOnScreen();
        searchPopMenu.show(jButton2, p.x, p.y);
        p.setLocation(p.x + 26, p.y + 16);
        searchPopMenu.setLocation(p);
    }//GEN-LAST:event_jButton2MouseClicked

    private void searchFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchFieldActionPerformed
// TODO add your handling code here:
        Hits hits = searcher.search(searchField.getText());
        if (selectedNode == null) {
            tree.setSelectionRow(0);
        }
        Document doc = null;
        table.clearSelection();
        tableModel.setNullData();
        int length = 0;
        EntrySet set;
        for (int i = 0; i < hits.length(); i++) {
            try {
                doc = hits.doc(i);
            } catch (CorruptIndexException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            try {
                if (doc.get(Indexer.CATEGORY_FIELD).indexOf(selectedNode.toString()) != -1) {
                    if (!new File(doc.get(Indexer.PATH_FIELD)).exists()) {
                        continue;
                    }
                    tableModel.getFeed(doc.get(Indexer.PATH_FIELD));
                    tableModel.addEntries();
                    set = tableModel.getEntrySet();
                    for (int j = 0; j < set.size(); j++) {
                        if (j < length) {
                            continue;
                        }
                        if (!set.getEntry(j).getTitle().equals(doc.get(Indexer.TITLE_FIELD))) {
                            set.removeEntry(j);
                            j--;
                        }
                    }
                    length++;
                }
            } catch (FeedException ex) {
                ex.printStackTrace();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        titleLabel.setText(applicationContext.getProperty("search.result.left.message") + " " +
                length + " " +
                applicationContext.getProperty("search.result.right.message"));
        if (length != 0) {
            tableModel.setData(false);
            tableModel.fireTableChanged(null);
            if (table.getColumnCount() > 0) {
                table.getColumnModel().getColumn(0).setMaxWidth(65);
            }
        }
    }//GEN-LAST:event_searchFieldActionPerformed

    private void filterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_filterActionPerformed
// TODO add your handling code here:
        int index = filter.getSelectedIndex();
        filterModel.setMode(index);
        modeChanged = true;
        tableModel.fireTableChanged(new TableModelEvent(tableModel));
    }//GEN-LAST:event_filterActionPerformed

    private void deleteEntryMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteEntryMenuActionPerformed
// TODO add your handling code here:
        int selectedRow = table.getSelectedRow();

    }//GEN-LAST:event_deleteEntryMenuActionPerformed

    private void updateAllMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateAllMenuActionPerformed
// TODO add your handling code here:
        updateAll.actionPerformed(new ActionEvent(toolBar.getComponentAtIndex(4), updateAll.hashCode(), "update all", -1));
    }//GEN-LAST:event_updateAllMenuActionPerformed

    private void updateMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateMenuActionPerformed
// TODO add your handling code here:
        update.actionPerformed(new ActionEvent(toolBar.getComponentAtIndex(3), update.hashCode(), "update", -1));
    }//GEN-LAST:event_updateMenuActionPerformed

    private void deleteMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteMenuActionPerformed
// TODO add your handling code here:
        delete.actionPerformed(new ActionEvent(toolBar.getComponentAtIndex(2), delete.hashCode(), "delete", -1));
    }//GEN-LAST:event_deleteMenuActionPerformed

    private void addCategoryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addCategoryActionPerformed
// TODO add your handling code here:
        newDir.actionPerformed(new ActionEvent(toolBar.getComponentAtIndex(1), newDir.hashCode(), "new category", -1));
    }//GEN-LAST:event_addCategoryActionPerformed

    private void addChannelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addChannelActionPerformed
// TODO add your handling code here:
        newCh.actionPerformed(new ActionEvent(toolBar.getComponentAtIndex(0), newCh.hashCode(), "new channel", -1));
    }//GEN-LAST:event_addChannelActionPerformed

    private void tableMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tableMousePressed
// TODO add your handling code here:
        int mods = evt.getModifiers();
        if ((mods & InputEvent.BUTTON3_MASK) != 0) { //Mouse rignt key
            int row = table.rowAtPoint(evt.getPoint());
            if (row < 0) {
                return;
            }
            table.changeSelection(row, 1, false, false);
            table.valueChanged(new ListSelectionEvent(table, row, row, false));
            tablePopMenu.show(table, evt.getX(), evt.getY());
        }
    }//GEN-LAST:event_tableMousePressed

    private void treeMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_treeMousePressed
// TODO add your handling code here:
        int mods = evt.getModifiers();
        if ((mods & InputEvent.BUTTON3_MASK) != 0) { //Mouse rignt key
            int rowLocation = tree.getRowForLocation(evt.getX(), evt.getY());
            if (rowLocation < 0) {
                return;
            }
            popMenu.show(tree, evt.getX(), evt.getY());
            TreePath treePath = tree.getPathForRow(rowLocation);
            tree.setSelectionPath(treePath);
            if (selectedNode == null) {
                return;
            }
            if (selectedNode.isFeed()) {
                add.setEnabled(false);
            } else {
                add.setEnabled(true);
            }
        }
    }//GEN-LAST:event_treeMousePressed

    private void urlFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_urlFieldActionPerformed
        //Clear all selected node
        tree.clearSelection();
        selectedNode = null;
        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
                String error = "";
                String url = urlField.getText();
                if (url == null || url.equals("")) {
                    return;
                }
                urlField.setEditable(false);
                tableModel.setNullData();
                try {
                    tableModel.setDataSource(url, true);
                } catch (FeedException ex) {
                    ex.printStackTrace();
                    error = ex.getMessage() + "\n" +
                            applicationContext.getProperty("connection.cause.text") +
                            ":" + ex.getCause().getMessage();
                    showError(url, error);
                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    urlField.setEditable(true);
                }
                String title = tableModel.getFeedTitle();
                tabbedPane.setTitleAt(0, title);
                titleLabel.setText(title);

            }
        });
        thread.start();
    }//GEN-LAST:event_urlFieldActionPerformed
    /**
     * Remove the tab from the tabbed pane as the mouse middle key clicked.
     * @param evt
     */
    private void tabbedPaneMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tabbedPaneMouseClicked
        //Be sure this is the third button of the mouse.
        int which = evt.getButton();
        if (which == 2) {
            //Be sure that the first tab won't be removed.
            if (tabbedPane.getSelectedIndex() != 0) {
                tabbedPane.remove(tabbedPane.getSelectedComponent());
            }
        }
    }//GEN-LAST:event_tabbedPaneMouseClicked

    private void checkUpdateMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkUpdateMenuItemActionPerformed
        /* At this time I think one user may want to update only once*/
        if (clientUpdater == null) {
            clientUpdater = new ClientUpdater();
            clientUpdater.setJProgressBar(progressBar);
            Thread thread = new Thread(clientUpdater);
            thread.start();
        }
    }//GEN-LAST:event_checkUpdateMenuItemActionPerformed

    private void helpContentMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_helpContentMenuItemActionPerformed
        JEditorPane pane = new JEditorPane();
        JScrollPane rollPane = new JScrollPane();
        StyleSheet style;
        rollPane.setViewportView(pane);
        pane.setContentType("text/html");
        HTMLDocument doc = (HTMLDocument) pane.getDocument();
        try {
            File file = new File(".");
            doc.setBase(new URL("file", "localhost", file.getAbsolutePath()));
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
        style = doc.getStyleSheet();
        style.addRule(css.getStyle());
        tabbedPane.addTab(applicationContext.getProperty("help.help.menu"),
                new JPanel().add(rollPane));
        try {
            pane.setPage("file://" + new File(".").getCanonicalPath() + "/" +
                    resourceContext.getProperty("docs.dir") + resourceContext.getProperty("help.html"));
        } catch (IOException ex) {
            Logger.getLogger(Window.class.getName()).log(Level.SEVERE, null, ex);
        }
        tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
}//GEN-LAST:event_helpContentMenuItemActionPerformed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /*try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            e.printStackTrace();
        }*/
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Window().setVisible(true);
            }
        });
    }

    public void showError(String url, String error) {
        JPanel errorTab = new JPanel();
        BorderLayout border = new BorderLayout();
        errorTab.setLayout(border);
        tabbedPane.addTab(url, null, errorTab);
        JLabel errorLabel = new JLabel(applicationContext.getProperty("connection.error.subtitle") +
                " " + url);
        errorLabel.setHorizontalAlignment(JLabel.CENTER);
        errorLabel.setForeground(new Color(187, 37, 34));
        JTextArea errorInfo = new JTextArea();
        errorInfo.setEditable(false);
        errorTab.add(errorLabel, BorderLayout.NORTH);
        errorInfo.setText(applicationContext.getProperty("connection.error.subtitle") +
                " " + error);
        errorTab.add(errorInfo, BorderLayout.CENTER);
        tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
    }

    public void valueChanged(TreeSelectionEvent e) {
        //Clear table's selection
        table.clearSelection();
        //Clear text area
        textArea.setText(null);
        if (e == null) {
            return;
        }
        TreePath treePath = e.getNewLeadSelectionPath();
        if (treePath == null) {
            return;
        }
        RSSTreeNode node = (RSSTreeNode) treePath.getLastPathComponent();
        selectedNode = node;
        if (node == null) {
            return;
        }
        tableModel.setNullData();
        if (!node.isFeed()) {
            titleLabel.setText(node.toString());
            tabbedPane.setTitleAt(0, node.toString());
            tableModel.showAll(node.getUserObject());
            filter.setSelectedIndex(0);
            if (table.getColumnCount() > 0) {
                table.getColumnModel().getColumn(0).setMaxWidth(65);
            }
            return;
        }
        String feedName = node.getTitle();
        String error = "";
        tabbedPane.setSelectedIndex(0);
        tabbedPane.setTitleAt(0, feedName);
        titleLabel.setText(feedName);
        try {
            if (!new File(GeneralUtils.getLocalChannelName(feedName, true, true)).exists()) {
                return;
            }
            tableModel.setDataSource(GeneralUtils.getLocalChannelName(feedName, true, true), true);
            filter.setSelectedIndex(0);
            if (table.getColumnCount() > 0) {
                table.getColumnModel().getColumn(0).setMaxWidth(65);
            }
        } catch (FeedException ex) {
            ex.printStackTrace();
            error = ex.getMessage() + "\n" + ex.getCause().getMessage();
            showError(GeneralUtils.getLocalChannelName(node.getTitle(), true, true), error);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    private void setSelectedNode(RSSTreeNode node) {
        selectedNode = node;
    }

    public static RSSTreeNode getSelectedNode() {
        return selectedNode;
    }

    public void dataChanged() {
        if (selectedNode != null) {
            if (selectedNode.isFeed()) {
                treeModel.reload(selectedNode);
            } else {
                treeModel.reload(selectedNode.getChildAt(selectedNode.getChildCount() - 1));
            }
        } else {
            tree.setSelectionRow(tree.getVisibleRowCount());
            treeModel.reload(selectedNode);
        }
    }

    public void rowAdded() {
    }

    /**
     * Response to user's clicking one row of the table
     * @param e
     */
    public void valueChanged(ListSelectionEvent e) {
        if (modeChanged) {
            modeChanged = false;
            return;
        }
        //Without the following statemnet,there is a bug.But I don't know why--I just code it.
        if (e.getFirstIndex() < 0) {
            return;
        }
        int selected = listModel.getLeadSelectionIndex();
        if (selected < 0) {
            return;
        }
        String url = null;
        Boolean marked = (Boolean) sortModel.getValueAt(selected, 0);
        if (marked == null) {
            return;
        }
        if (!marked && table.getSelectedColumn() != 0) {
            tableModel.setFlag(true);
            sortModel.setValueAt(true, selected, 0);
        }
        int a = filterModel.getOriginalRow(selected);
        String html = tableModel.getSelectedEntry(a).toHTML();
        textArea.setText(html);
        textArea.setCursor(new Cursor(Cursor.TEXT_CURSOR));
    }

    public void actionPerformed() {
        EntrySet entries = updater.getNewFeedEntry();
        if (entries == null) {
            return;
        }
        for (int i = 0; i < entries.size(); i++) {
            tableModel.addEntryRow(entries.getEntry(i));
        }
        treeModel.reload(selectedNode);
    }

    public void hyperlinkUpdate(HyperlinkEvent e) {
        if (e == null) {
            return;
        }
        JEditorPane pane = new JEditorPane();
        JScrollPane rollPane = new JScrollPane();
        rollPane.setViewportView(pane);
        if (e.getEventType() == EventType.ACTIVATED) {
            try {
                tabbedPane.addTab(e.getURL().toString(), new JPanel().add(rollPane));
                pane.setPage(e.getURL());
                tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
            } catch (IOException ex) {
                ex.printStackTrace();
                pane.setText(applicationContext.getProperty("server.not.found.error"));
            }
        }
    /*String bash = "gnome-terminal " + e.getURL() ;
    try {
    Runtime.getRuntime().exec(bash);
    } catch (IOException ex) {
    ex.printStackTrace();
    }*/
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenu add;
    private javax.swing.JMenuItem addCategory;
    private javax.swing.JMenuItem addChannel;
    private javax.swing.JPanel bottomPanel;
    private javax.swing.JMenuItem checkUpdateMenuItem;
    private javax.swing.JMenuItem deleteEntryMenu;
    private javax.swing.JMenuItem deleteMenu;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JComboBox filter;
    private javax.swing.JMenuItem googleSearch;
    private javax.swing.JMenuItem helpContentMenuItem;
    private javax.swing.JMenu helpMenu;
    private javax.swing.JMenuItem homePageMenuItem;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JSeparator jSeparator7;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JSplitPane jSplitPane2;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JPopupMenu popMenu;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JTextField searchField;
    private javax.swing.JPopupMenu searchPopMenu;
    private javax.swing.JMenuItem starMenu;
    private javax.swing.JMenuItem summarySearch;
    private javax.swing.JPanel tabHeader;
    private javax.swing.JTabbedPane tabbedPane;
    private javax.swing.JTable table;
    private javax.swing.JPopupMenu tablePopMenu;
    private javax.swing.JMenuItem technoratiSearch;
    private javax.swing.JEditorPane textArea;
    private javax.swing.JLabel titleLabel;
    private javax.swing.JMenuItem titleSearch;
    private javax.swing.JToolBar toolBar;
    private javax.swing.JToolBar toolBar2;
    private javax.swing.JPanel toolBarPanel;
    private javax.swing.JTree tree;
    private javax.swing.JMenuItem updateAllMenu;
    private javax.swing.JMenuItem updateMenu;
    private javax.swing.JTextField urlField;
    // End of variables declaration//GEN-END:variables
    private ResourceContext resourceContext = ResourceContext.getResourceContext();
    private ApplicationContext applicationContext = ApplicationContext.getApplicationContext();
    private DefaultTreeModel treeModel;
    private RSSTreeNode root = new RSSTreeNode(
            applicationContext.getProperty("category.root.name"));
    private RSSTreeCellRenderer renderer = new RSSTreeCellRenderer();
    private RSSTreeHelper treeHelper;
    private MenuAction newCh = new MenuAction(applicationContext.getProperty("channel.new.button.text"));
    private MenuAction newDir = new MenuAction(applicationContext.getProperty("category.new.button.text"));
    private MenuAction delete = new MenuAction(applicationContext.getProperty("delete.button.text"));
    private MenuAction update = new MenuAction(applicationContext.getProperty("update.button.text"));
    private MenuAction updateAll = new MenuAction("Update All");
    private ChannelList channelList;
    private XMLTableModel tableModel;
    private static RSSTreeNode selectedNode;
    private ListSelectionModel listModel;
    private Updater updater;
    private CascadeStyleSheet css;
    private boolean modeChanged = false;
    private XMLDocumentFactory xml = new XMLDocumentFactory();
    private Searcher searcher = new Searcher();
    private SortableTableModel sortModel;
    private FilterableTableModel filterModel;
    private ClientUpdater clientUpdater;
}
